package com.own.business.pay.module.alipay.service;

import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeCloseModel;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.own.business.pay.common.constant.ConstantPay;
import com.own.business.pay.common.em.PayEnum;
import com.own.business.pay.common.exception.PayException;
import com.own.business.pay.core.aop.AopPayService;
import com.own.business.pay.core.base.BasePayService;
import com.own.business.pay.core.model.PayOrderModel;
import com.own.business.pay.core.model.PayResultModel;
import com.own.business.pay.core.model.RefundOrderModel;
import com.own.business.pay.core.service.BillHistoryService;
import com.own.business.pay.entity.po.BillHistory;
import com.own.business.pay.module.alipay.property.AliPayProperty;
import com.own.business.pay.module.alipay.util.AlipayUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * AlipayService
 *
 * @author chenxueli
 * @date 2023-07-10 10:21:00
 */
@Slf4j
@Component
@AopPayService(PayEnum.Method.ALIPAY)
public class AlipayService implements BasePayService {

    @Resource
    private AliPayProperty aliPayProperty;
    @Resource
    private AlipayUtil alipayUtil;
    @Resource
    private BillHistoryService billHistoryService;

    /**
     * 获取客户端信息
     *
     * @return 客户端信息
     */
    private DefaultAlipayClient client() {
        // 实例化客户端
        return new DefaultAlipayClient(
                aliPayProperty.getServerUrl(),
                aliPayProperty.getAppId(),
                AliPayProperty.PRIVATE_KEY,
                "json",
                aliPayProperty.getCharset(),
                AliPayProperty.PUBLIC_KEY,
                aliPayProperty.getSignType()
        );
    }

    /**
     * 支出方法
     *
     * @param type  支付方式
     * @param model 支付订单
     * @return 支付凭证
     */
    @Override
    public PayResultModel pay(PayEnum.Type type, PayOrderModel model) {
        return switch (type) {
            case MOBILE -> alipayUtil.app(client(), model);
            case QR_CODE -> alipayUtil.qrcode(client(), model);
            default -> throw new PayException("支付类型不支持");
        };
    }

    /**
     * 收入方法（提现）
     *
     * @param model 收入订单
     */
    @Override
    public void income(PayOrderModel model) {
        throw new PayException("支付宝不支持收入提现方法");
    }

    /**
     * 查询订单
     *
     * @param outTradeNo 商户订单号
     * @return 账单信息
     */
    @Override
    public BillHistory query(String outTradeNo) {
        return null;
    }

    /**
     * 订单退款
     * <p>
     * 1. 同一笔交易的退款至少间隔3s后发起
     * <p>
     * 2. 请严格按照接口文档中的参数进行接入。若在此接口中传入【非当前接口文档中的参数】会造成【退款失败或重复退款】。
     * <p>
     * 3. 该接口不可与其他退款产品混用。若商户侧同一笔退款请求已使用了当前接口退款的情况下，【再使用其他退款产品进行退款】可能会造成【重复退款】。
     * <p>
     * 4. 退款成功判断说明：接口返回fund_change=Y为退款成功，fund_change=N或无此字段值返回时需通过退款查询接口进一步确认退款状态。详见退款成功判断指导。注意，接口中code=10000，仅代表本次退款请求成功，不代表退款成功。
     *
     * @param outTradeNo 商户订单
     * @param model      退款信息
     */
    @Override
    public void refund(String outTradeNo, RefundOrderModel model) {
        var alipayClient = client();
        var request = new AlipayTradeRefundRequest();
        var bizContent = new JSONObject();
        bizContent.put("out_trade_no", outTradeNo);
        bizContent.put("refund_amount", model.getRefund() / 100);
        bizContent.put("out_request_no", model.getRefundNo());
        bizContent.put("refund_reason", model.getReason());
        request.setBizContent(bizContent.toString());
        try {
            alipayClient.execute(request);
        } catch (AlipayApiException e) {
            log.error("支付宝退款异常，错误信息", e);
            throw new PayException("支付宝退款异常");
        }
    }

    /**
     * 查询单笔退款信息
     *
     * @param outTradeNo  商户订单
     * @param outRefundNo 商户退款单号
     * @return 账单信息
     */
    @Override
    @SneakyThrows
    public BillHistory queryRefund(String outTradeNo, String outRefundNo) {
        // 查询对应的订单是否完成
        var bill = billHistoryService.getByRefundNo(outRefundNo);
        if (bill == null) {
            throw new PayException("退款单号不存在");
        }
        if (ConstantPay.Status.COMPLETE_SUCCESS == bill.getStatus()) {
            return bill;
        }
        var client = client();
        var request = new AlipayTradeFastpayRefundQueryRequest();
        var bizContent = new JSONObject();
        bizContent.put("out_trade_no", outTradeNo);
        bizContent.put("out_request_no", outRefundNo);
        request.setBizContent(bizContent.toString());
        request.setNotifyUrl(aliPayProperty.getNotifyUrl());
        var response = client.execute(request);
        if (response.isSuccess()) {
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }
        return bill;
    }

    /**
     * 关闭订单
     *
     * @param outTradeNo 商户订单号
     */
    @Override
    public void close(String outTradeNo) {
        var client = client();
        var request = new AlipayTradeCloseRequest();
        var model = new AlipayTradeCloseModel();
        model.setOutTradeNo(outTradeNo);
        request.setBizModel(model);
        request.setNotifyUrl(aliPayProperty.getNotifyUrl());
        try {
            var response = client.execute(request);
            if (!response.isSuccess()) {
                log.error("支付宝支付失败，错误信息：{}", response.getMsg());
                if (Objects.equals(response.getCode(), "40004")) {
                    return;
                }
                throw new PayException("支付宝关闭订单失败");
            }
        } catch (AlipayApiException e) {
            throw new PayException(e);
        }
    }

}
